from typing import List

from llvmlite import ir
from .base import get_function_cls
from MelodieAllegro.exteral_functions.builtin_functions_interface_classes.base import PMBuiltinFunction


class PMRandomFloat(PMBuiltinFunction):

    def __init__(self):
        super().__init__('random')

    def __call__(self, builder: ir.IRBuilder, args: List = None, arg_types: List = None, name=''):
        from ..builtin_func_types import builtins
        from ...types import PMBasicType, double
        assert len(args) == len(arg_types) == 0
        return builtins.random_float(builder, [], name), PMBasicType(double)


class PMRandomInteger(PMBuiltinFunction):

    def __init__(self):
        super().__init__('randint')

    def __call__(self, builder: ir.IRBuilder, args: List = None, arg_types: List = None, name=''):
        from ..builtin_func_types import builtins
        from ...types import PMBasicType, double, integer
        assert len(args) == len(arg_types) == 2
        assert args[0].type == integer
        assert args[1].type == integer
        return builtins.random_integer(builder, args, name), PMBasicType(integer)


class PMUniformRandomNumber(PMBuiltinFunction):

    def __init__(self):
        super().__init__('uniform')

    def __call__(self, builder: ir.IRBuilder, args: List = None, arg_types: List = None, name=''):
        from ..builtin_func_types import builtins
        from ...types import PMBasicType, double
        assert len(args) == len(arg_types) == 2
        assert args[0].type == double
        assert args[1].type == double
        return builtins.uniform(builder, args, name), PMBasicType(double)


class PMSampleIndex(PMBuiltinFunction):

    def __init__(self):
        super().__init__('sample_index')

    def __call__(self, builder: ir.IRBuilder, args: List = None, arg_types: List = None, name=''):
        from ..builtin_func_types import builtins
        from ...types import PMBasicType, double, integer, PMArrayType
        assert len(args) == len(arg_types) == 2
        assert args[0].type == integer
        assert args[1].type == integer

        ptr = builtins.sample_index(builder, args, name)
        array_type = PMArrayType(integer)
        return array_type.from_buffer(builder, builder.ptrtoint(ptr, integer), args[1], 'integer', name)


random_function_interfaces = get_function_cls(globals())
